package top.dashuizhuyu.study;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import top.dashuizhuyu.study.entity.SysPermission;
import top.dashuizhuyu.study.entity.SysRole;
import top.dashuizhuyu.study.entity.User;
import top.dashuizhuyu.study.service.UserService;

/**
 * <p>
 *
 * 这个类帮助我们解决用户注册的密码散列问题，
 * 当然我们还需要使用同样的算法来保证在登陆的时候密码能够被散列成相同的字符串。
 * 如果两次散列的结果不同系统就无法完成密码比对，
 * 因此在计算散列因子的时候我们不能引入变量，
 * 例如我们可以将username作为salt因子加入散列算法，
 * 但是不能选择password或datetime，具体原因各位请手动测试。
 *
 * 另外为了帮助Shiro能够正确为当前登陆用户做认证和赋权，
 * 我们需要实现自定义的Realm。
 * 具体来说就是实现doGetAuthenticationInfo和doGetAuthorizationInfo，
 * 这两个方法前者负责登陆认证后者负责提供一个权限信息。
 *
 * @author dashuizhuyu@foxmail.com
 * @date 2020/1/22 11:28
 **/
public class EnceladusShiroRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        String username = (String) principals.getPrimaryPrincipal();

        User user = userService.findUserByName(username);

        for (SysRole role : user.getRoles()) {
            authorizationInfo.addRole(role.getRole());
            for (SysPermission permission : role.getPermissions()) {
                authorizationInfo.addStringPermission(permission.getName());
            }
        }
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        User user = userService.findUserByName(username);

        if (user == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),
                ByteSource.Util.bytes(user.getCredentialsSalt()), getName());
        return authenticationInfo;
    }

}
